import json
from datetime import datetime
from pytz import timezone
from client.redis_client import r
from dao.es_dao.card_dao import get_card, update_battery, update_online_status
from model.es.card import ElectronicCardModel
from model.wristband_models import BatteryData
from utils.date_utils import timestamp_to_date
from utils.mongo_util import db


async def handle_step(battery: BatteryData):
    """
        根据8分钟上传步数，来判断是否在活动，更新活动状态和活动强度状态，
        并记录，需要记录活跃度而不是当前上传值，超过50步，记入有效工作时长，
        根据配置来设置合理性，低强度，中强度，高强度
        阈值区间设置。这8分钟记入有效工作时间并标记工作强度。
    """
    # 获取和上一次步数记录之间的步数差和时间，存入es单独表。
    imei = battery.device_id
    timestamp = battery.timestamp
    device_step = battery.pedometer
    step = 0
    card_doc: ElectronicCardModel = None
    _id = None
    try:
        card_doc = await get_card(imei)
        _id = card_doc.es_id
    except Exception as e:
        print(f'Error occurred while getting card: {e}')
        db.wristband_logs_error.insert_one({'imei': imei, 'error': '未获取到card', 'timestamp': timestamp_to_date(timestamp)})
    if _id is not None and card_doc is not None:
        date = datetime.fromtimestamp(timestamp, timezone('Asia/Shanghai'))
        last_step_dict = await get_last_step(imei)
        if last_step_dict is not None:
            if date.date() == timestamp_to_date(last_step_dict['timestamp']).date():
                step = device_step - last_step_dict['step']
                # 如果步数差小于0，则步数差为0
            else:
                step = 0
        else:
            step = 0
        r.hset('step_last', imei, json.dumps({'step': device_step, 'timestamp': timestamp}))
        await update_battery(battery.battery,_id)
        await save_work_time(imei, step, date)
        await update_online_status(timestamp, _id)

    # 更新运动状态 根据阈值不同，记录有效工作时间，并且标记不同的工作强度。并且更新运动强度状态，为健康判断做
    # 并存入活动状态，如果这个值没有，则为离线或关机。8分钟TTL。key 值为 online_%imei


# 定义一个异步函数，用于保存工作时间
async def save_work_time(imei: str, step: int, date: datetime):
    intensity = await get_intensity(step)
    r.setex(f'intensity_{imei}', 500, json.dumps({'intensity': intensity, 'step': step, 'date': date.timestamp()}))
    # 将数据存入mongodb
    if step > 0:
        in_fence = r.hget('in_fence', imei)
        if in_fence is None:
            in_fence = 0
        else:
            in_fence = int(in_fence)
        db.work_time.insert_one({'imei': imei, 'step': step, 'date': date, 'intensity': intensity,
                                 'inFence': in_fence})


async def get_intensity(step):
    # 根据步数返回强度
    intensity = 0  # 默认为0
    if 1 <= step <= 50:  # 动弹状态
        intensity = 1
    elif 50 < step <= 250:  # 低强度
        intensity = 2
    elif 250 < step <= 500:  # 中强度
        intensity = 3
    elif step > 500:  # 高强度
        intensity = 4
    return intensity


# 定义一个异步函数，用于获取上一次步数记录
async def get_last_step(imei: str):
    try:
        last_step_dict = json.loads(r.hget('step_last', imei))
        return last_step_dict
    except Exception as e:
        print(f'Error occurred while getting last step json: {e}')
        return None


# 创建函数 如果获取到就是 值，获取不到就是0，并且处理异常 返回整形

async def get_intensity_redis(device_id: str) -> dict:
    """
        获取设备强度
    """
    try:
        intensity = r.get(f'intensity_{device_id}')
        if intensity is None:
            return {'intensity': 0, 'step': 0, 'date': 0}
        return json.loads(intensity.decode('utf-8'))
    except Exception as e:
        print(f'Error occurred while getting intensity from redis: {e}')
        return {'intensity': -1, 'step': 0}


async def get_online_redis(imei_list: list) -> list:
    """
        获取设备在线状态
    """
    keys_to_query = [f"intensity_{imei}" for imei in imei_list]
    results = r.mget(keys_to_query)
    online_result = []
    for i in range(0, len(imei_list), 1):
        if results[i] is None:
            online_result.append({'imei': imei_list[i], 'online': -1})
        else:
            online_result.append({'imei': imei_list[i], 'online': int(results[i])})
    return online_result


# 定义一个异步函数，用于更新充电状态
async def update_charge_status(imei, param):
    # 传入两个参数，imei和param

    pass


async def get_battery_es(imei: str):
    pass


async def handle_battery(data: dict):
    """
        处理电池信息
    """
    imei = data['device_id']
    battery = data['battery']
    # 更新电池状态
    # 获取es index p_electron_card 中电池电量 battery 字段，如果当前电量高于es中电量，则更新es p_electron_card 充电状态为true，如果低于es中电量，则更新es充电状态为false 
    # 如果当前电量低于es中电量，则更新es充电状态为false，并记录电池电量变化
    # 如果当前电量高于es中电量，则更新es充电状态为true，并记录电池电量变化
    # 如果当前电量等于es中电量，则不更新es充电状态，并记录电池电量变化

    # 获取es index p_electron_card 中电池电量 battery 字段
    battery_es = await get_battery_es(imei)
    if battery_es is None:
        return
    if battery > battery_es:
        # 更新es充电状态为true
        await update_charge_status(imei, True)

    elif battery < battery_es:
        # 更新es充电状态为false
        await update_charge_status(imei, False)


# 根据IMEI list 获取对应时间段内的有效工作时间。和各各强度下的工作时长

async def get_valid_work_time_detail(imei_list: list[str], start_date, end_date):
    # 获取对应时间段内的有效工作时间
    pipeline = [
        # 1. 过滤符合条件的文档
        {"$match": {
            "imei": {"$in": imei_list},
            "date": {"$gte": start_date, "$lte": end_date},
            "inFence": 1
        }},

        # 2. 按日期排序（可选，根据业务需求决定是否保留）
        {"$sort": {"date": 1}},

        # 3. 第一次分组：按 imei 和 intensity 组合分组，统计每个强度的总时间、总步数
        {"$group": {
            "_id": {"imei": "$imei", "intensity": "$intensity"},
            "total_time": {"$sum": 8},  # 每条数据的工作时长为8分钟
            "total_steps": {"$sum": "$step"}
        }},

        # 4. 第二次分组：按 imei 分组，汇总总时间和总步数，并保留 intensity 的统计结果
        {"$group": {
            "_id": "$_id.imei",  # 主键为 imei
            "total_time_all": {"$sum": "$total_time"},  # 所有强度的总时间
            "total_steps_all": {"$sum": "$total_steps"},  # 所有强度的总步数
            "intensity_stats": {  # 每个 imei 对应的 intensity 统计结果数组
                "$push": {
                    "intensity": "$_id.intensity",
                    "time": "$total_time",  # 仅统计不同强度的时间（步数可选）
                    "steps": "$total_steps"
                }
            }
        }}
    ]
    result = db.work_time.aggregate(pipeline).to_list(length=None)

    return result


async def get_valid_work_time_detail_by_person(imei: str, start_date, end_date):
    # 获取对应时间段内的有效工作时间
    pipeline = [
        # 1. 过滤符合条件的文档（单IMEI查询）
        {"$match": {
            "imei": imei,
            "date": {"$gte": start_date, "$lte": end_date},
            "inFence": 1
        }},

        # 2. 时区转换核心逻辑（UTC转北京时间）
        {"$addFields": {
            # 转换为北京时间：增加8小时（8*60*60000毫秒）
            "beijing_time": {
                "$add": ["$date", 8 * 60 * 60000]
            }
        }},

        # 3. 提取北京时间维度
        {"$addFields": {
            "date_str": {"$dateToString": {
                "format": "%Y-%m-%d",
                "date": "$beijing_time"  # 使用转换后的北京时间
            }},
            "hour": {
                "$hour": "$beijing_time"  # 提取北京时间的小时
            }
        }},

        # 4. 按日期+小时+强度分组
        {"$group": {
            "_id": {
                "date": "$date_str",
                "hour": "$hour",
                "intensity": "$intensity"
            },
            "total_time": {"$sum": 8},
            "total_steps": {"$sum": "$step"}
        }},

        # 5. 按日期+小时聚合
        {"$group": {
            "_id": {
                "date": "$_id.date",
                "hour": "$_id.hour"
            },
            "date": {"$first": "$_id.date"},
            "hour": {"$first": "$_id.hour"},
            "total_duration": {"$sum": "$total_time"},
            "total_steps": {"$sum": "$total_steps"},
            "intensity_details": {
                "$push": {
                    "intensity": "$_id.intensity",
                    "duration": "$total_time",
                    "steps": "$total_steps"
                }
            }
        }},

        # 6. 按日期和小时排序
        {"$sort": {
            "date": 1,
            "hour": 1
        }},

        # 7. 输出字段结构调整
        {"$project": {
            "_id": 0,
            "date": 1,
            "hour": 1,
            "total_duration": 1,
            "total_steps": 1,
            "intensity_details": 1
        }}
    ]

    return db.work_time.aggregate(pipeline).to_list(length=None)


async def get_valid_work_time_detail_group(imei_list: list[str], start_date, end_date):
    # 获取对应时间段内的有效工作时间
    pipeline = [
        # 1. 基础过滤
        {"$match": {
            "imei": {"$in": imei_list},
            "date": {"$gte": start_date, "$lte": end_date},
            "inFence": 1
        }},

        # 2. 添加固定工作时间字段
        {"$addFields": {
            "work_time": 8  # 单位：分钟
        }},

        # 3. 按设备、日期、强度分组（兼容旧版本）
        {"$group": {
            "_id": {
                "imei": "$imei",
                "date": {
                    "$dateToString": {  # 替代 $dateTrunc
                        "format": "%Y-%m-%d",
                        "date": "$date",
                        "timezone": "Asia/Shanghai"
                    }
                },
                "intensity": "$intensity"
            },
            "total_steps": {"$sum": "$step"},
            "total_time": {"$sum": "$work_time"}
        }},

        # 4. 重置字段名（移除_id嵌套）
        {"$project": {
            "imei": "$_id.imei",
            "date": "$_id.date",
            "intensity": "$_id.intensity",
            "total_steps": 1,
            "total_time": 1,
            "_id": 0
        }},
        {"$sort": {
            "date": 1,
            "imei": 1,  # 升序排列（1 表示升序，-1 表示降序）
            "intensity": 1
        }}
    ]

    result = db.work_time.aggregate(pipeline).to_list(length=None)
    return result
